Pressidian
花园入口
笔记
项目
关于
实验室
GitHub
花园入口
笔记
项目
关于
实验室
GitHub

KNOWLEDGE PATHS

笔记库
当前位置
笔记库/前端/面试/八股/TS

as const

4 分钟阅读 · Note

目录树 578 篇

            • any、unknown 和 never
            • as const
            • First
          • 进阶篇题目列表
          • DOM&浏览器 API
          • HTTP&网络
          • TS
          • Vue
        • 可投递企业
      • 前端技术栈
    • 笔记目录
    • CLAUDE.md
    • Vue 组件与 Render 函数

关联笔记 6

↗any、unknown 和 never同一路径↗First同一路径↗1基础篇共同主题↗2进阶篇共同主题↗4手写篇共同主题↗5AI面试共同主题

我需要先查看这个文件的上下文,了解 as const 具体应用在什么地方。

用户询问的是关于 as const 的含义。他们引用了文件 g:\Save\Grogramming\CodeForge\daedalus/\packages\services\src\archetypes-service.ts 的第19行,其中包含 } as const;。

这是一个 TypeScript 语法问题。as const 是 TypeScript 中的类型断言,用于将表达式的类型推断为最具体的字面量类型,而不是更宽泛的类型。

我需要先查看这个文件的上下文,了解 as const 具体应用在什么地方,以便给出准确的解释。让我先读取这个文件的内容。

用户询问的是第19行的 as const 是什么。我已经看到了代码,现在可以解释这个 TypeScript 语法。

as const 是 TypeScript 中的类型断言,用于将对象字面量的类型推断为最具体的类型(字面量类型),而不是更宽泛的类型。

在这个例子中:

const ServiceErrorType = {
  notFound: "not_found",
  invalidInput: "invalid_input",
} as const;

如果没有 as const,TypeScript 会推断 ServiceErrorType 的类型为:

{
  notFound: string;
  invalidInput: string;
}

有了 as const 后,类型被推断为:

{
  readonly notFound: "not_found";
  readonly invalidInput: "invalid_input";
}

这意味着:

  1. 属性值被推断为字面量类型 "not_found" 和 "invalid_input",而不是宽泛的 string
  2. 属性变为只读(readonly)
  3. 后续在第22行使用 (typeof ServiceErrorType)[keyof typeof ServiceErrorType] 时,可以获取到具体的字面量类型联合 "not_found" | "invalid_input"

这样做的好处是类型更精确,能够提供更好的类型检查和自动补全。 as const 是 TypeScript 中的常量断言(const assertion),用于让 TypeScript 将对象字面量推断为最具体的类型(字面量类型),而不是更宽泛的类型。


具体作用

在这段代码中:

const ServiceErrorType = {
  notFound: "not_found",
  invalidInput: "invalid_input",
} as const;

没有 as const 时,TypeScript 会推断类型为:

{
  notFound: string;      // 宽泛的 string 类型
  invalidInput: string;
}

有 as const 时,TypeScript 会推断为:

{
  readonly notFound: "not_found";      // 精确的字面量类型
  readonly invalidInput: "invalid_input";
}

为什么需要它

这段代码的关键用途在第 22 行:

type: (typeof ServiceErrorType)[keyof typeof ServiceErrorType];

由于 as const 的作用,(typeof ServiceErrorType)[keyof typeof ServiceErrorType] 的结果是 "not_found" | "invalid_input"(字面量类型联合),而不是宽泛的 string 类型。

这样做的好处:

  1. 类型更精确:确保只能使用预定义的错误类型值
  2. 更好的类型检查:如果传入其他字符串会报错
  3. 自动补全支持:IDE 会提示可用的错误类型选项
  4. 属性只读:防止意外修改这些常量值

用户问为什么不直接写成联合类型,而是用 as const 和 typeof 的方式。我需要解释这种模式的优势和用途。

用户提到的代码:

const ServiceErrorType = {
  notFound: "not_found",
  invalidInput: "invalid_input",
} as const;

export type ServiceError = {
  type: (typeof ServiceErrorType)[keyof typeof ServiceErrorType];
  message: string;
};

用户问为什么不直接写成:

type ServiceErrorType = "not_found" | "invalid_input";

export type ServiceError = {
  type: ServiceErrorType;
  message: string;
};

我需要解释两种方式的区别和使用场景:

  1. 直接联合类型的优缺点
  2. 使用 as const + typeof 的优缺点
  3. 为什么项目选择了这种方式

主要原因可能包括:

  • 需要同时拥有运行时值和类型
  • 避免重复定义
  • 便于维护和扩展
  • 支持自动生成类型
  • 类型安全和运行时访问的统一

我需要查看更多代码来确认这个模式在项目中的使用方式。


const ServiceErrorType = {
  notFound: "not_found",
  invalidInput: "invalid_input",
} as const;

export type ServiceError = {
  type: (typeof ServiceErrorType)[keyof typeof ServiceErrorType];
  message: string;
};

你问得很有道理!让我分析一下两种写法的区别。


直接写成联合类型当然可以

如果只是定义类型,直接写成联合类型更简洁:

type ServiceErrorType = "not_found" | "invalid_input";

export type ServiceError = {
  type: ServiceErrorType;
  message: string;
};

为什么项目要这么写?

这种 const + as const + typeof 的模式有几个关键优势:

同时拥有运行时值和类型

通过 const ServiceErrorType,代码不仅定义了类型,还创建了一个运行时可用的对象。这意味着可以:

// 运行时检查错误类型
if (error.type === ServiceErrorType.notFound) {
  // 处理 notFound 错误
}

// 动态生成错误
throw { type: ServiceErrorType.invalidInput, message: "..." };

避免重复定义

如果直接写联合类型,当需要运行时值时,还得单独定义常量:

// 重复定义
type ServiceErrorType = "not_found" | "invalid_input";
const ServiceErrorType = {
  notFound: "not_found",
  invalidInput: "invalid_input",
};

而 as const 模式只需定义一次,类型通过 typeof 自动推导。

类型安全与自动补全

使用对象属性访问(如 ServiceErrorType.notFound)比直接写字符串 "not_found" 更安全,IDE 会提供自动补全,避免拼写错误。

便于维护和扩展

当需要新增错误类型时,只需在对象中添加一个属性,类型会自动更新:

const ServiceErrorType = {
  notFound: "not_found",
  invalidInput: "invalid_input",
  databaseError: "database_error",  // 新增
} as const;
// ServiceError['type'] 自动包含 "database_error"

什么时候用哪种方式?

场景推荐写法
只需要类型,不需要运行时值直接联合类型
需要同时使用类型和运行时值as const + typeof 模式
需要在多个地方引用这些值as const + typeof 模式

总结

这个项目采用的是类型和运行时值统一管理的模式,虽然看起来稍微复杂一点,但在实际开发中更安全、更易维护。如果你只是定义纯类型,直接写联合类型完全没问题!